#include "StdAfx.h"
#include "Settings.h"

#include <string.h>
#include <projects.h>

#include "FileReader.h"
#include "Util.h"

#ifdef _DEBUG
#include "crtdbg.h"
#endif

#define DATAITEM(item, type, def) { TEXT(#item), item, type, def }

// SETTINGS
CIniHandler::SDataItem settingsItems[] = {
    DATAITEM(sLanguage,                 ivString, TEXT("english")),
    DATAITEM(sLanguagePath,             ivString, TEXT("Lang")),
    DATAITEM(sTheme,                    ivString, TEXT("default")),
    DATAITEM(sThemePath,                ivString, TEXT("Themes")),
    DATAITEM(sScrollThresh,             ivInt,    TEXT("8")),
    DATAITEM(sScrollBounceTime,         ivInt,    TEXT("200")),
    DATAITEM(sScrollSearchTime,         ivInt,    TEXT("300")),
    DATAITEM(sLongTapDelay,             ivInt,    TEXT("300")),
    DATAITEM(sSelectorShowTime,         ivInt,    TEXT("300")),
    DATAITEM(sSelectorHideTime,         ivInt,    TEXT("200")),
    { 0 }
  };

CIniHandler CSettings::s_Settings;
bool        CSettings::s_isSmartphone = false;

bool CSettings::Initialize(const TCHAR* szSettingsFile)
{
  // detect platform type
  TCHAR szPlatform[256] = { 0 };
  if (SystemParametersInfo(SPI_GETPLATFORMTYPE, 256, szPlatform, 0))
  {
    s_isSmartphone = (_tcsicmp(szPlatform, TEXT("Smartphone")) == 0);
  }
  else
  { // Smartphone creates an access denied error on SystemParametersInfo
    if (GetLastError() == ERROR_ACCESS_DENIED)
      s_isSmartphone = true;
  }

  CString sSettings = GetAppFolder();
  sSettings += szSettingsFile;
  return s_Settings.Create(sSettings, settingsItems);
}

void CSettings::Terminate()
{
  s_Settings.Destroy();
}

CString CSettings::GetAppFolder()
{
  TCHAR szPath[MAX_PATH*2];

  // Get program file path
  ::GetModuleFileName(NULL, szPath, MAX_PATH*2);
  // Crop name of executable
  TCHAR* pstr = _tcsrchr(szPath, TEXT('\\'));
  if (pstr) *(++pstr) = 0;

  return CString(szPath);
}

CString CSettings::GetStoragePath(int cardIndex)
{
  CString path = TEXT("\\");

  WIN32_FIND_DATA fd;
  HANDLE hCF = ::FindFirstFile(TEXT("\\*"), &fd);
  if (INVALID_HANDLE_VALUE == hCF)
    return path;

  const int CF_CARDS_FLAGS = (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_TEMPORARY);

  int index = 0;
  do
  {
    if ((fd.dwFileAttributes & CF_CARDS_FLAGS) == CF_CARDS_FLAGS && index == cardIndex)
    {
      path += fd.cFileName;
      path += TEXT("\\");
      break;
    }
    index++;
  }
  while (::FindNextFile(hCF, &fd));

  ::FindClose(hCF);

  return path;
}

bool CIniHandler::Create(const TCHAR* szFile, const SDataItem* dataItems)
{
  if (szFile == NULL)
    return false;

  CFileReader fr;
  if (!fr.Open(szFile))
    return false;

  return Create(fr, dataItems);
}

bool CIniHandler::Create(CBaseReader& r, const SDataItem* dataItems)
{
  Destroy();
  m_dataItems = dataItems;
  return Load(r);
}

void CIniHandler::Destroy()
{
  CIniValueMap::iterator iter = m_settingsMap.begin();
  while(iter != m_settingsMap.end())
  {
    if (iter->second)
      delete iter->second;
    iter++;
  }
  m_settingsMap.clear();
}

bool CIniHandler::Load(CBaseReader& r)
{
  MapGenerate();

  CString key, value;

  while (r.ReadPair(key, value))
  {
    MapApply(key.GetString(), value.GetString());
  }

  return true;
}

const CIniValue* CIniHandler::GetValue(int key) const
{
  CIniValueMap::const_iterator val = m_settingsMap.find(key);
  if (val != m_settingsMap.end())
    return val->second;
  else
    return NULL;
}

CIniValue* CIniHandler::GetValue(int key)
{
  CIniValueMap::const_iterator val = m_settingsMap.find(key);
  if (val != m_settingsMap.end())
    return val->second;
  else
    return NULL;
}

void CIniHandler::MapGenerate()
{
  if (!m_dataItems)
    return;

  const SDataItem* item = m_dataItems;
  while(item->name != NULL)
  {
    CIniValue* pVal = CIniValueFactory::Get(item->type, item->def);
    if (pVal)
      m_settingsMap.insert(std::make_pair(item->id, pVal));
    item++;
  }
}

void CIniHandler::MapApply(const TCHAR* key, const TCHAR* val)
{
  if (!key || !val || !m_dataItems)
    return;
  const SDataItem* item = m_dataItems;
  while(item->name != NULL)
  {
    if (::_tcsicmp(item->name, key) == 0)
    {
      CIniValueMap::iterator iter = m_settingsMap.find(item->id);
      if (iter != m_settingsMap.end() && iter->second)
      {
        iter->second->Set(val);
      }
      break;
    }
    item++;
  }
}
